<?php

namespace App\Http\Controllers;
use App\Exceptions\BusinessException;
use App\Http\Controllers\Api\ApiController;
use App\Models\GoodsPicPrimaryModel;
use App\Models\Jst\JstImagesModel;
use App\Models\Jst\PicInfoModel;
use App\Models\JstNotifyModel;
use App\Models\JstPushModel;
use App\Models\OrderGoodsModel;
use App\Models\OrderModel;
use App\Models\SpecModel;
use App\Models\SupplyModel;
use App\Utils\ResponseEnum;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Foundation\Application;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class JstController extends ApiController
{
    const CACHE_KEY = 'JST_TOKEN_CACHE';
    private string $key = 'a2861b921a3a4472ac9f8e4b4b7f9b23';
    private string $secret = '424d4c63d8e247fe8bc4b356fb2bdf98';
    private int $shopId = 13869274;
    private string $apiHost = 'https://openapi.jushuitan.com';
    private string $accessTokenPath = '/openWeb/auth/getInitToken';
    private string $refreshTokenPath = '/openWeb/auth/refreshToken';
    private string $skuUploadPath = '/open/jushuitan/itemsku/upload';
    private string $orderUploadPath = '/open/jushuitan/orders/upload';
    private string $orderLabelPath = '/open/jushuitan/order/label/upload';
    private string $orderRemarkPath = '/open/jushuitan/order/remark/upload';
    private string $orderCancelPath = '/open/jushuitan/orderbyoid/cancel';
    private string $saleGoodsUploadPath = '/open/api/goods/inneropen/goods/addgoods';
	private string $imageUploadPath = '/open/api/goods/inneropen/oss/uploadimage';

    /**
     * 获取token
     * @return JsonResponse
     * @throws GuzzleException
     */
    public function getToken(): JsonResponse
    {
        $data = $this->getTokenCache();
        return $this->success($data);
    }

    /**
     * 刷新token并重新生成缓存
     * @return JsonResponse
     * @throws GuzzleException
     */
    public function refreshToken(): JsonResponse
    {
        $data = $this->getTokenCache();
        if (!isset($data['refresh_token']))
            return $this->fail(ResponseEnum::JST_FRESH_TOKEN_NOT_FOUND);
        $refreshToken = $data['refresh_token'];
        $response = GuzzlePost($this->apiHost, $this->refreshTokenPath, $this->getTokenParams([ 'refresh_token' => $refreshToken, 'scope' => 'all']));
        $data = json_decode($response, true);
        if ($data['code'] === 0)
            Cache::put(self::CACHE_KEY, $data['data'], 15 * 24 * 3600);
        return $this->success($data);
    }

    /**
     * 上传商品SKU
     * @return JsonResponse
     * @throws GuzzleException
     * @throws BusinessException
     */
    public function uploadGoodsSku(): JsonResponse
    {
        $goodsId = $this->verifyInteger('goods_id');
        $skuCollection = SpecModel::where('goods_id', $goodsId)->where('jst', 0)->where('jst_count', 0)->limit(50)->get();
        if ($skuCollection) {
            $items = $this->getUploadGoodsData($skuCollection);
            $response = $this->doCurlPost($this->skuUploadPath, $items);
            $data = json_decode($response, true);
            if ($data['code'] === 0) {
                $uploadedGoodsSns = [];
                foreach ($data['data']['datas'] as $v) {
                    $uploadedGoodsSns[] = $v['sku_id'];
                }
                SpecModel::whereIn('goods_sn', $uploadedGoodsSns)->update(['jst' => 1, 'jst_count' => 1]);
            }
        }
        return $this->success($skuCollection);
    }

    /**
     * 同步订单
     * @param Request $request
     * @return JsonResponse
     * @throws BusinessException
     * @throws GuzzleException
     */
    public function uploadOrder(Request $request): JsonResponse
    {
        $orderNo = $this->verifyString('order_no');
        $order = OrderModel::where('order_no', $orderNo)->where('pay_status', 1)->first();
        if ($order) {
            $postData = [$this->getUploadOrderData($order)];
            $response = $this->doCurlPost($this->orderUploadPath, $postData);
            $data = json_decode($response, true);
            if ($data['code'] === 0) {
                $jst_id = $data['data']['datas'][0]['o_id'];
                $order->jst_id = $jst_id;
                $order->jst = 1;
                $order->save();
            }
        }
        return $this->success();
    }

    /**
     * 同步订单客服备注
     * @return JsonResponse
     * @throws BusinessException
     * @throws GuzzleException
     */
    public function uploadOrderCustomerServiceRemark(): JsonResponse
    {
        $jstId = $this->verifyNumeric('jst_id');
        $remark = $this->verifyString('remark');
        $postData = ['o_id' => $jstId, 'remark' => $remark, 'is_append' => false];
        $response = $this->doCurlPost($this->orderRemarkPath, $postData);
        return $this->success(json_decode($response));
    }

    /**
     * 同步订单标签
     * @return JsonResponse
     * @throws BusinessException
     * @throws GuzzleException
     */
    public function uploadOrderLabel(): JsonResponse
    {
        $orderNo = $this->verifyString('order_no');
        $jstId = $this->verifyNumeric('jst_id');
        $label = \request()->input('content', '配货完成');
        $postData = ['o_id' => $jstId, 'so_id' => $orderNo, 'labels' => [$label], 'action_type' => 1];
        $response = $this->doCurlPost($this->orderLabelPath, $postData);
        $data = json_decode($response, true);
        if ($data['code'] === 0)
            JstPushModel::where('order_no', $orderNo)->where('code', 0)->update(['code' => 1, 'push_count' => 1, 'updated_at' => Carbon::now()->toDateTimeString()]);
        else
            JstPushModel::where('order_no', $orderNo)->where('code', 0)->increment('push_count');
        return $this->success($data);
    }

    /**
     * 关闭订单，回收单号
     * @return void
     * @throws GuzzleException
     */
    public function cancelOrder(): void
    {
        $orderData = OrderModel::where('jst', 1)->where('refund_status', 1)->where('cancel', 0)->limit(10)->get(['id', 'jst_id'])->toArray();
        $jstIds = array_column($orderData, 'jst_id');
        if (count($jstIds) > 0) {
            $post = [
                'o_ids'    => $jstIds,
                'cancel_type' => '申请退款'
            ];
            $response = $this->doCurlPost($this->orderCancelPath, $post);
            $data = json_decode($response, true);
            var_dump($data);
            if ($data['code'] === 0 || $data['code'] === 130)
                OrderModel::whereIn('jst_id', $jstIds)->update(['cancel' => 1]);
        }
    }

    /**
     * 上传图片到聚水潭分销
     * @return JsonResponse
     * @throws GuzzleException
     */
    public function uploadImage(): JsonResponse
    {
        $goodsId = JstImagesModel::where('finished', 0)->value('goods_id');
        $images = PicInfoModel::where('pid', $goodsId)->where('type', 1)->whereNull('jst_url')
            ->where('width', '>', 0)->limit(5 )->get();
        if (!$images->isEmpty()) {
            foreach ($images as $image) {
                $response = $this->doCurlPost($this->imageUploadPath, ['original_url' => $image->file_url]);
                $data = json_decode($response, true);
                if ($data['code'] === 0) {
                    $image->jst_url = $data['data'];
                    $image->save();
                }
            }
        } else
            JstImagesModel::where('goods_id', $goodsId)->update(['finished' => 1]);
        return $this->success($images);
    }

    /**
     * 添加商品到聚水潭分销
     * @return JsonResponse
     * @throws GuzzleException
     */
    public function addSaleGoods(): JsonResponse
    {
        $goodsId = JstImagesModel::where('doned', 0)->where('finished', 1)->value('goods_id');
        if ($goodsId) {
            $goods = GoodsPicPrimaryModel::where('ID', $goodsId)->select(['PName', 'ToySn'])->first();
            $imageCollection = PicInfoModel::where('pid', $goodsId)->whereNotNull('jst_url')->select(['width', 'height', 'file_url', 'jst_url'])->orderByDesc('pic_id')->get();
            $allImages = $imageCollection->map(function ($item) {
                return $item->jst_url;
            })->toArray();
            $data = [
                'item_name' =>  $goods ? $goods->PName : '',
                'style_code' => $goods ? $goods->ToySn : '',
                'first_spec_name' => '颜色',
                'second_spec_name' => '尺寸',
                'item_photo' => [
                    'item_spare_image' => array_slice($allImages, 0, 40),
                    'item_detail_images' => $allImages,
                    'main_image_list' => array_slice(array_values($imageCollection->filter(function ($item) {
                        return $item->width == $item->height;
                    })->map(function ($item) {
                        return $item->jst_url;
                    })->toArray()), 0, 9),
                ],
                'item_sku_list' => $this->getSaleGoodsSku($goodsId, $imageCollection)
            ];
            $response = $this->doCurlPost($this->saleGoodsUploadPath, $data);
            $responseData = json_decode($response, true);
            if ($responseData['code'] === 0)
                JstImagesModel::where('goods_id', $goodsId)->update(['doned' => 1]);
            else {
                Log::error('上传分销失败, 商品序号:' . $goodsId);
                Log::debug('上传数据', $data);
                Log::error('上传分销失败原因:', $responseData);
                JstImagesModel::where('goods_id', $goodsId)->update(['doned' => -1]);
            }
        }
        return $this->success($goodsId);
    }

    /**
     * 聚水潭通知回调
     * @param Request $request
     * @return Application|Response|\Illuminate\Contracts\Foundation\Application|ResponseFactory
     */
    public function notify(Request $request): Application|Response|\Illuminate\Contracts\Foundation\Application|ResponseFactory
    {
        JstNotifyModel::create(['content' => json_encode($request->all(), JSON_UNESCAPED_UNICODE)]);
        if ($request->has('l_id') && $request->has('so_id')) {
            $order = OrderModel::where('order_no', $request->input('so_id'))->first();
            if ($order && $request->input('l_id')) {
                $order->express_no = $request->input('l_id');
                $new = mb_substr($request->input('logistics_company'), 0, 2, 'utf-8');
                $order->express_company = $new . mb_substr($order->express_company, 2);
                $order->express_status = 1;
                $order->save();
            }
        }
        return response(['code' => '0', 'msg' => '执行成功']);
    }

    /**
     * 设置token缓存
     * @return void
     * @throws GuzzleException
     */
    public function setTokenCache(): void
    {
        $data = $this->doCurlGetTokenData();
        if (isset($data['access_token']))
            Cache::put(self::CACHE_KEY, $data, 15 * 24 * 3600);
    }

    /**
     * 获取token缓存
     * @return mixed
     * @throws GuzzleException
     */
    public function getTokenCache(): mixed
    {
        if (!Cache::has(self::CACHE_KEY))
            $this->setTokenCache();
        return Cache::get(self::CACHE_KEY);
    }

    /**
     * 远程获取token数据
     * @return array|mixed
     * @throws GuzzleException
     */
    private function doCurlGetTokenData(): mixed
    {
        $response = GuzzlePost($this->apiHost, $this->accessTokenPath, $this->getTokenParams(['code' => rand(100000, 999999)]));
        $data = json_decode($response, true);
        return $data['code'] === 0 ? $data['data'] : [];
    }

    /**
     * 获取上传的商品数据
     * @param $collection
     * @return array
     */
    private function getUploadGoodsData($collection): array
    {
        $data = [];
        $skuItem = $collection->first();
        if ($skuItem) {
            $supply = SupplyModel::where('ID', $skuItem->sid)->select('CName', 'floor', 'room')->first();
            foreach ($collection as $item) {
                $goodsName = mb_substr($supply->floor, 0, 1) . $supply->room . ' ' . getFilterGoodsName($item->goods_name);
                $data[] = [
                    'sku_id'                => $item->goods_sn,
                    'i_id'                  => $item->goods_sn,
                    'name'                  => $goodsName,
                    'properties_value'      => $item->color . ';' . $item->size,
                    'shop_id'               => $this->shopId,
                    's_price'               => $item->price,
                    'c_price'               => $item->price,
                    'market_price'          => $item->price,
                    'pic'                   => $item->thumbnail,
                    'sku_pic'               => $item->thumbnail,
                    'weight'                => round($item->weight / 1000, 2),
                    'supplier_name'         => $supply->CName,
                ];
            }
        }
        return ['items' => $data];
    }

    /**
     * 获取订单数据
     * @param $order
     * @return array
     */
    private function getUploadOrderData($order): array
    {

        $payMoney = $order->goods_total + $order->express_fee + $order->daifa_fee + $order->check_fee + $order->package_fee + $order->brand_fee + $order->wishcard_fee - $order->gold;
        return [
            'shop_id'             => $this->shopId,
            'so_id'               => $order->order_no,
            'order_date'          => Carbon::parse($order->created_at)->toDateTimeString(),
            'shop_status'         => 'WAIT_SELLER_SEND_GOODS',      // 'TRADE_CLOSED',
            'shop_buyer_id'       => $order->username,
            'receiver_state'      => $order->province_text,
            'receiver_city'       => $order->city_text,
            'receiver_district'   => $order->district_text,
            'receiver_address'    => $order->addr,
            'receiver_name'       => $order->name,
            'receiver_phone'      => $order->mobile,
            'receiver_mobile'     => $order->mobile,
            'pay_amount'          => round($payMoney, 2),
            'freight'             => round($order->express_fee, 2),
            'buyer_message'       => $order->remark,
            'remark'              => getOrderAddonFeeText($order),
            'logistics_company'   => $order->express_company,
            'lc_id'               => $this->getJstExpressCode($order->express_company),
            'items'               => $this->getOrderGoodsList($order->order_no, $order->refund_status),
            'pay'                 => [
                'outer_pay_id'      => $order->order_no,
                'pay_date'          => Carbon::parse($order->updated_at)->toDateTimeString(),
                'payment'           => '支付宝',
                'seller_account'    => $order->username,
                'buyer_account'     => '毛绒之家',
                'amount'            => round($payMoney, 2)
            ],
            'seller_flag'         => 3,
        ];
    }

    /**
     * 获取订单商品数据
     * @param string $orderNo
     * @param int $refundStatus
     * @return array
     */
    private function getOrderGoodsList(string $orderNo, int $refundStatus): array
    {
        $goods = OrderGoodsModel::where('order_no', $orderNo)->get();
        if (request()->input('cancel_status', 0))
            $refundStatusText = 'closed';
        else
            $refundStatusText = $refundStatus > 0 ? 'waiting' : '';
        $data = [];
        foreach ($goods as $k => $item) {
            if (empty($refundStatusText) && $item->refund)
                $refundStatusText = 'success';
            $data[] = [
                'sku_id'            => $item->goods_sn,
                'shop_sku_id'       => $item->goods_sn,
                'pic'               => $item->thumbnail,
                'name'              => mb_substr($item->floor, 0, 1) . $item->room . ' ' . getFilterGoodsName($item->goods_name),
                'properties_value'  => $item->color . ';' . $item->size . ';' . $item->weight,
                'amount'            => round($item->goods_num * $item->price, 2),
                'base_price'        => round($item->price, 2),
                'qty'               => intval($item->goods_num),
                'remark'            => $item->goods_remark,
                'outer_oi_id'       => $orderNo . $k,
                'refund_status'     => $refundStatusText,       // waiting：等待退款，success：成功退款，closed：关闭
            ];
        }
        return $data;
    }

    /**
     * 聚水潭快递公司编码
     * @param string $expressCompany
     * @return string
     */
    private function getJstExpressCode(string $expressCompany): string
    {

        return match ($expressCompany) {
            '邮政（菜鸟）'   => 'POSTB',
            '中通（菜鸟）'   => 'ZTO',
            '申通（菜鸟）'   => 'STO',
            '极兔（菜鸟）'   => 'JTSD',
            '极兔（拼多多）' => 'JTSD.1',
            '极兔（抖音）'   => 'JTSD.2',
            '顺丰（菜鸟）'   => 'SF',
            default        => 'JTSD',
        };
    }

    /**
     * 获取分销商品数据
     * @param $goodsId
     * @param $imageCollection
     * @return array
     */
    private function getSaleGoodsSku($goodsId, $imageCollection) {
        $specs = SpecModel::where('goods_id', $goodsId)->select(['goods_id', 'goods_sn', 'color', 'size', 'price', 'weight', 'thumbnail'])->get();
        $skus = [];
        foreach ($specs as $item) {
            $pic = $imageCollection->where('file_url', $item->thumbnail)->first();
            $skus[] = [
                'first_spec_value_name' => $item->color,
                'second_spec_value_name' => $item->size,
                'item_code' => $item->goods_sn,
                'supply_price' => $item->price,
                'sale_price' => $item->price,
                'weight' => $item->weight,
                'pic' => $pic ? $pic->jst_url : '',
            ];
        }
        return $skus;
    }

    /**
     * 签名
     * @param $params
     * @return string
     */
    private function getSign($params): string
    {
        if (empty($params))
            return '';
        ksort($params);
        $str = '';
        foreach ($params as $key => $val) {
            if ( !empty($key) && $key != 'sign' )
                $str = $str . $key . $val;
        }
        return bin2hex(md5($this->secret . $str, true));
    }

    /**
     * 获取token传参
     * @param array $extra
     * @return array
     */
    private function getTokenParams(array $extra): array
    {
        $params = [
            'app_key'     => $this->key,
            'timestamp'   => time(),
            'grant_type'  => 'authorization_code',
            'charset'     => 'utf-8',
        ];
        $params = array_merge($params, $extra);
        $params['sign'] = $this->getSign($params);
        return $params;
    }

    /**
     * 执行接口上传和同步
     * @param $path
     * @param $data
     * @return string
     * @throws GuzzleException
     */
    private function doCurlPost($path, $data): string
    {
        $tokenData = $this->getTokenCache();
        $params = [
            'app_key'     => $this->key,
            'access_token'=> $tokenData['access_token'],
            'timestamp'   => time(),
            'charset'     => 'utf-8',
            'version'     => '2',
            'biz'         => json_encode($data, JSON_UNESCAPED_UNICODE)
        ];
        $params['sign'] = $this->getSign($params);
//        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        return curlPost($this->apiHost . $path, [], $params);
    }
}
